package com.demo.webapp.ui.table.displayer;

import java.net.MalformedURLException;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspException;

import org.apache.struts2.ServletActionContext;
import org.apache.struts2.views.freemarker.ScopesHashModel;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;

import com.demo.common.FormatUtils;
import com.demo.common.StringUtils;
import com.demo.core.dao.base.support.PageSupport;
import com.demo.webapp.ui.ComponentBase;
import com.demo.webapp.ui.displayer.FreemarkerDisplayerSupport;
import com.demo.webapp.ui.paging.PageComponent;
import com.demo.webapp.ui.table.TableComponent;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.util.ValueStack;

import freemarker.template.Template;
import freemarker.template.TemplateModel;

/**
 * 
 * @author ryuu.kk
 *
 */
public class FreemarkerTableDisplayer extends FreemarkerDisplayerSupport<TableComponent> {

	@Override
	public String getType() {
		// TODO Auto-generated method stub
		return null;
	}
	
	private String prefix = "_table_source";

	private Object source;
	@Override
	protected boolean preTemplateProcess(TableComponent component, Template template,
			TemplateModel templateModel) {
		boolean result = true;

		ScopesHashModel hash = (ScopesHashModel) templateModel;
		this.source = component.getSource();
		this.prefix = component.getProperty();
		PageSupport pageSupport = component.getPageSupport();
		//add something.
		// 表格配置
		hash.put("table", component);
		// 表格数据
		hash.put("this", this.source);
		// 分页信息
		hash.put("pageSupport", pageSupport);
		//使模板支持jsp标签
        if (getPageContext().getAttribute("tableId") != null) {
        	hash.put("tableId", getPageContext().getAttribute("tableId"));
        }
        hash.put("displayer", this);
        
        //如果存在分页支持,则将其放入上下文中,尽管用户或许没有设置分页的pagesize参数
        if (pageSupport != null) {
        	PageComponent page = new PageComponent();
        	page.setPageSupport(pageSupport);
        	page.setPage(component.getPage());
        	// 分页数据
    		hash.put("page", page);
			try {
				// 设置location值(当没有指定该值时,进行计算)
				setPageLocation(page);
			} catch (MalformedURLException m) {
				log.error("Incorrect action or forward: " + m.getMessage());
				page.setLocation("#");
			} catch (JspException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} 
        }
        
        //压入值栈
        //setValueStack(prefix, buildResult(), false);
        
		return result;
	}
	
	/**
	 * 返回Cell的 内容--针对Cell的property属性的取值设置,也可以根据渲染的数据源进行简单数据查找
	 * (使用format格式化)
	 * @param key 属性名,使用ognl表达式描述
	 * @param format 格式化字符串
	 * @return Object 显示内容
	 * @throws SecurityException
	 * @throws NoSuchFieldException
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 */
	@SuppressWarnings("rawtypes")
	public Object property(String key, String format) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
		
		ValueStack vs = getCurrentValueStack();
		
		//String value = vs.findString(prefix + "[" + index + "]." + key);
		Object value = vs.findValue(prefix + key);
		
		if (value instanceof Boolean) {
			return getFormat((Boolean) value, format);
		}
		if (value instanceof String) {
			return getFormat((String) value, format );
		}
		if (value instanceof Date) {
			return getFormat((Date) value, format);
		}
		if (value instanceof Double) {
			return getFormat((Number) value, format);
		}
		if (value instanceof Long) {
			return value;
		}
		if (value instanceof List) {
			return getFormat((List) value, format);
		}
		if (value instanceof Number) {
			return getFormat((Number) value, format);
		}
		return value;
	}
	
	/**
	 * 返回Cell内容--针对innerHtml属性的处理,也可以处理带有占位符的内容
	 * @param innerHtml 带有占位符的字符串
	 * @param index 当前Cell所在的第index行
	 * @return Object Cell结果
	 * @throws SecurityException
	 * @throws NoSuchFieldException
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 */
	public Object property(String innerHtml, int index) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
		
		ValueStack vs = getCurrentValueStack();
		// 提取关键字
		String[] keywords = FormatUtils.keywords(innerHtml);
		Map<String, Object> params = null;
		if (keywords != null) {
			params = new HashMap<String, Object>();
			for (String keyword : keywords) {
				Object value = vs.findValue(prefix + "[" + index + "]." + keyword);
				params.put(keyword, value);
			}
		}
		return FormatUtils.format(innerHtml, params);
	}
	
	// ~~ --------------------------------------------------------------------------------------
	//Format boolean
	protected String getFormat(Boolean booleanValue, String format) {
		String[] args = {"YES" , "NO"};
		if (StringUtils.isNotEmpty(format)) {
			args = format.split(":");
		}
		return booleanValue != null ? (booleanValue.equals(Boolean.TRUE) ? args[0] : args[1]) : null;
	}
	
	//Format string
	protected Object getFormat(String strValue, String format) {
		Object parseValue = strValue;
		Map<String, Object> formatMap = new HashMap<String, Object>();
		if (format != null && format.length() > 0) {
			ObjectMapper mapper = new ObjectMapper(); // can reuse, share globally
			try {
				formatMap = mapper.readValue(format.getBytes(), new TypeReference<Map<String, Object>>() {});
				parseValue = formatMap.get(strValue);
			} catch (Exception e) {
				parseValue = e.getMessage();
			} 
		}
		return parseValue;
	}
	
	//Format date
	protected String getFormat(Date dateValue, String format) {
		String arg = "yyyy/MM/dd";
		if (StringUtils.isNotEmpty(format)) {
			arg = format;
		}
		
		SimpleDateFormat df = new SimpleDateFormat(arg);
		return df.format(dateValue);
	}
	
	//Format number
	protected String getFormat(Number numberValue, String format) {
		String arg = "#";
		if (StringUtils.isNotEmpty(format)) {
			arg = format;
		}
		DecimalFormat df = new DecimalFormat(arg);
		
		return df.format(numberValue);
	}
	
	@SuppressWarnings("unchecked")
	protected static Object getFormat(List listValue, String format) {
		if (StringUtils.isEmpty(format)) {
			return listValue;
		}
		return FormatUtils.format(format, listValue);
	}
	
	public static final void main(String[] args) {
		//String result = getFormat(new ArrayList(), "abc{name}:{value}");
		//System.out.print(result);
	}
	
	protected ValueStack getCurrentValueStack() {
		
		ActionContext ctx = ServletActionContext.getActionContext((HttpServletRequest) getPageContext().getRequest());
		ValueStack vs = ctx.getValueStack();
		return vs;
	}
	
	/**
	 * 当location为空时，设置location地址 如果page不为空,则使用page地址作为location地址
	 * 如果page也为空,则使用forward地址作为location地址 FIXME 根据通配符${}查找相应数据
	 * 
	 * @param base Page组件对象
	 */
	protected void setPageLocation(ComponentBase base) throws MalformedURLException, JspException {
		HttpServletRequest request = (HttpServletRequest) getPageContext().getRequest();
		setLocation(base);
		String url = base.getLocation();

		// 检查是有存在EL通配符
		if ((url != null) && (url.indexOf("${") > -1)) {
			String queryString = null;

			if (url.indexOf("?") > -1) {
				queryString = url.substring(url.indexOf("?") + 1);
				url = url.substring(0, url.indexOf(queryString));
			}
			// variable is in the URL
			if (queryString != null) {
				base.setUrl(url + parseString(queryString, request));
			} else {
				// parse the URL, rather than the queryString
				base.setUrl(parseString(url, request).toString());
			}
		} else {
			base.setUrl(url);
		}

		HttpServletResponse response = (HttpServletResponse) getPageContext().getResponse();
		if (base.getUrl() != null) {
			base.setUrl(response.encodeURL(base.getUrl()));
		}

		// do all contained menus
		List<ComponentBase> subMenus = base.getSubComponents();

		if (subMenus != null && subMenus.size() > 0) {
			for (ComponentBase subMenu : subMenus) {
				this.setPageLocation(subMenu);
			}
		}
	}

	protected void setLocation(ComponentBase page) throws MalformedURLException {
		// if the location attribute is null, then set it with a context
		// relative page
		// attribute if it exists
		if (page.getLocation() == null) {
			try {
				if (page.getPage() != null) {
					HttpServletRequest request = (HttpServletRequest) getPageContext().getRequest();
					page.setLocation(request.getContextPath() + getPage(page.getPage()));
					HttpServletResponse response = (HttpServletResponse) getPageContext().getResponse();
					page.setLocation(response.encodeURL(page.getLocation()));
				} else if (page.getForward() != null) {
					HttpServletRequest request = (HttpServletRequest) getPageContext().getRequest();
					page.setLocation(request.getContextPath() + getPage(page.getForward()));
					HttpServletResponse response = (HttpServletResponse) getPageContext().getResponse();
					page.setLocation(response.encodeURL(page.getLocation()));
				}
			} catch (NoClassDefFoundError e) {
				if (page.getForward() != null) {
					throw new MalformedURLException("forward '"
							+ page.getForward() + "' invalid - no struts.jar");
				}
			}
		}
	}

	/**
	 * 返回page属性 如果page没有设置"/",将page增加一个 "/"
	 * 
	 * @param page page属性
	 */
	protected String getPage(String page) {
		if (page.startsWith("/")) {
			return page;
		} else {
			page = "/" + page;
		}

		return page;
	}

	private StringBuffer parseString(String str, HttpServletRequest request) {
		StringBuffer sb = new StringBuffer();

		while (str.indexOf("${") >= 0) {
			sb.append(str.substring(0, str.indexOf("${")));

			String variable = str.substring(str.indexOf("${") + 2,
					str.indexOf("}"));
			// 对page,request,session（如果有效的话）和application范围进行查找
			String value = String.valueOf(getPageContext().findAttribute(variable));

			if (value == null) {
				// 如果不存在,则查看请求参数
				value = request.getParameter(variable);
			}

			// value仍然为空,使用Struts2的值栈? no.
			if (value == null) {
				log.warn("Value for '"
						+ variable
						+ "' not found in getPageContext() or as a request parameter");
			}

			sb.append(value);
			str = str.substring(str.indexOf("}") + 1, str.length());
		}

		return sb.append(str);
	}
}
